using System;
using System.Linq.Expressions;
using System.Text;

namespace MathService.MathParser
{
    [NotImplemented]
    public class LaTeXExpressionVisitor : ExpressionVisitorEx
    {
        private StringBuilder f_Result;
        private readonly object f_Convert_ThreadLock = new object();

        public string Convert(Expression expression)
        {
            lock(f_Convert_ThreadLock)
            {
                f_Result = new StringBuilder();
                Visit(expression);
                return f_Result.ToString();
            }
        }

        protected override Expression VisitBinary(BinaryExpression b)
        {
            var left = Visit(b.Left);

            var symbol = "";
            switch(b.NodeType)
            {
                case ExpressionType.Add:
                    symbol = "+";
                    break;
                case ExpressionType.Subtract:
                    symbol = "-";
                    break;
                case ExpressionType.Multiply:
                    symbol = "*";
                    break;
                case ExpressionType.Divide:
                    symbol = "/";
                    break;
                case ExpressionType.Power:
                    symbol = "^";
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
                //break;
            }
            f_Result.Append(symbol);

            var right = Visit(b.Right);
            var conversion = Visit(b.Conversion);
            return left != b.Left || right != b.Right || conversion != b.Conversion
                ? (b.NodeType == ExpressionType.Coalesce && b.Conversion != null
                    ? Expression.Coalesce(left, right, conversion as LambdaExpression)
                    : Expression.MakeBinary(b.NodeType, left, right, b.IsLiftedToNull, b.Method))
                : b;
        }

        protected override Expression VisitConstant(ConstantExpression c)
        {
            f_Result.Append(c.Value);
            return base.VisitConstant(c);
        }
    }
}